#ifndef COORDINATOR_HPP_
#define COORDINATOR_HPP_

#include "system/thread/Thread.hpp"
#include "kit/event/Event.hpp"
#include "kit/user/UserMap.hpp"
#include "kit/tool/Sequencer.hpp"
#include "kit/container/ThreadSafeQueue.hpp"


namespace KitCoordinator
{
	/**
	 * The main purpose of this class is to coordinate the thread that receives events
	 * and the one that receives users requests. It gets as a parameters a reference
	 * to a queue that is updated by event receiving thread, and a map containing users.
	 * In this way, it is easy to read an event from the queue and execute it on connected
	 * users. The class aggregates also a Sequencer, that is generating the next sequence
	 * number that should be processed. Thanks to that we may process incoming events
	 * in the correct order.  The objects of this class are working as a separate thread
	 * and using thread safe containers, so all mutual exclusion is done on the level
	 * of containers.
	 */
	class Coordinator : public SystemThread::Thread
	{
	public:
		/**
		 * Creates an instance of coordinator object and sets the fields.
		 *
		 * \param iQueue an object of ThreadSafeQueue, that contains incoming events
		 * \param iMap an object of ThreadSafeMap, that contains active users
		 */
		Coordinator(
					KitContainer::ThreadSafeQueue<KitEvent::Event*> * iQueue,
					KitUser::UserMap * iMap,
					unsigned int iMaxEventsAtTime)
						:_eventQueue(iQueue),_userMap(iMap),_seq(1),MAX_EVENTS_AT_TIME(iMaxEventsAtTime){}
		/**
		 * Just destructor. Nothing special.
		 */
		virtual ~Coordinator(){}
	private:
		/**
		 * Thread implementation, derived from the Thread class. This method is called as
		 * a separate Thread.
		 */
		virtual void runThreadImpl();
		/**
		 * Takes some number of elements from the event queue and executes them. The number
		 * of elements taken from the queue is limited by the value of MAX_EVENTS_AT_TIME
		 * constant. The value of this constant should be set according to observation of
		 * numbers of connected users and incoming events, so the method processQueue will
		 * compute similar amount of time to cleanOfflineUsers.
		 */
		void processQueue();

		// keeps users connected to the system
		KitUser::UserMap * _userMap;
		// keeps incoming users
		KitContainer::ThreadSafeQueue<KitEvent::Event*> * _eventQueue;
		// generates the next sequence number that should be processed
		KitTool::Sequencer _seq;
		// represents the maximum number of elements that are processed within processQueue
		const unsigned int MAX_EVENTS_AT_TIME;
	};
}



#endif /* COORDINATOR_HPP_ */
